import * as THREE from 'three'
import { sailisiGraphData, nodeTypeColors } from '../data/sailisiSampleData.js'

/**
 * 几何体生成器 - 负责生成节点和边的几何体
 */
export class GeometryGenerator {
  constructor(graph) {
    this.graph = graph
  }

  /**
   * 获取节点颜色（RGB数值）
   */
  getNodeColorRGB(node) {
    const nodeData = sailisiGraphData.nodes[node.name]
    const nodeType = nodeData?.type || 'default'
    const colorHex = nodeTypeColors[nodeType] || '#ffffff'
    
    // 将十六进制颜色转换为RGB
    const color = new THREE.Color(colorHex)
    return {
      r: color.r,
      g: color.g,
      b: color.b
    }
  }

  /**
   * 生成节点和边的几何体
   */
  generate() {
    const nodeGeometry = this.generateNodeGeometry()
    const edgeGeometry = this.generateEdgeGeometry()
    
    return { nodeGeometry, edgeGeometry }
  }

  /**
   * 生成节点几何体
   */
  generateNodeGeometry() {
    const nodes = Object.values(this.graph.nodes).sort((a, b) => a.id - b.id)
    const nodeCount = nodes.length
    
    if (nodeCount === 0) {
      return new THREE.BufferGeometry()
    }

    // 创建位置数组
    const positions = new Float32Array(nodeCount * 3)
    const colors = new Float32Array(nodeCount * 3)
    const sizes = new Float32Array(nodeCount)
    const nodeIds = new Float32Array(nodeCount)

    nodes.forEach((node, index) => {
      // 随机初始位置
      positions[index * 3] = (Math.random() - 0.5) * 1000
      positions[index * 3 + 1] = (Math.random() - 0.5) * 1000
      positions[index * 3 + 2] = (Math.random() - 0.5) * 1000

      // 根据度数设置颜色强度
      const degree = node.getDegree()
      const intensity = Math.min(1, degree / 10) // 归一化度数
      
      colors[index * 3] = 0.5 + intensity * 0.5     // R
      colors[index * 3 + 1] = 0.3 + intensity * 0.7 // G  
      colors[index * 3 + 2] = 0.8 + intensity * 0.2 // B

      // 根据度数设置大小
      sizes[index] = Math.max(5, Math.min(20, degree * 2))*2
      
      // 节点ID
      nodeIds[index] = node.id
    })

    const geometry = new THREE.BufferGeometry()
    geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3))
    geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3))
    geometry.setAttribute('size', new THREE.BufferAttribute(sizes, 1))
    geometry.setAttribute('nodeId', new THREE.BufferAttribute(nodeIds, 1))

    return geometry
  }

  /**
   * 生成边几何体
   */
  generateEdgeGeometry() {
    const edges = Object.values(this.graph.edges)
    const nodes = this.graph.nodes
    
    if (edges.length === 0) {
      return new THREE.BufferGeometry()
    }

    // 计算所需的顶点数量
    let vertexCount = 0
    edges.forEach(edge => {
      const sourceNode = nodes[edge.source]
      const targetNode = nodes[edge.target]
      if (sourceNode && targetNode) {
        vertexCount += 2 // 每条边需要2个顶点
      }
    })

    const positions = new Float32Array(vertexCount * 3)
    const colors = new Float32Array(vertexCount * 3)
    const weights = new Float32Array(vertexCount)

    let vertexIndex = 0

    edges.forEach(edge => {
      const sourceNode = nodes[edge.source]
      const targetNode = nodes[edge.target]
      
      if (sourceNode && targetNode) {
        // 源节点位置
        positions[vertexIndex * 3] = sourceNode.position.x || (Math.random() - 0.5) * 1000
        positions[vertexIndex * 3 + 1] = sourceNode.position.y || (Math.random() - 0.5) * 1000
        positions[vertexIndex * 3 + 2] = sourceNode.position.z || (Math.random() - 0.5) * 1000

        // 目标节点位置
        positions[(vertexIndex + 1) * 3] = targetNode.position.x || (Math.random() - 0.5) * 1000
        positions[(vertexIndex + 1) * 3 + 1] = targetNode.position.y || (Math.random() - 0.5) * 1000
        positions[(vertexIndex + 1) * 3 + 2] = targetNode.position.z || (Math.random() - 0.5) * 1000

        // 获取源节点和目标节点的颜色
        const sourceColor = this.getNodeColorRGB(sourceNode)
        const targetColor = this.getNodeColorRGB(targetNode)
        
        // 源节点颜色（边的起点）
        colors[vertexIndex * 3] = sourceColor.r
        colors[vertexIndex * 3 + 1] = sourceColor.g
        colors[vertexIndex * 3 + 2] = sourceColor.b

        // 目标节点颜色（边的终点）
        colors[(vertexIndex + 1) * 3] = targetColor.r
        colors[(vertexIndex + 1) * 3 + 1] = targetColor.g
        colors[(vertexIndex + 1) * 3 + 2] = targetColor.b

        // 权重
        const weight = edge.getWeight()
        weights[vertexIndex] = weight
        weights[vertexIndex + 1] = weight

        vertexIndex += 2
      }
    })

    const geometry = new THREE.BufferGeometry()
    geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3))
    geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3))
    geometry.setAttribute('weight', new THREE.BufferAttribute(weights, 1))

    return geometry
  }

  /**
   * 更新节点位置
   */
  updateNodePositions(nodeGeometry, positions) {
    if (!nodeGeometry || !positions) return
    
    const positionAttribute = nodeGeometry.attributes.position
    if (positionAttribute && positions.length >= positionAttribute.count * 3) {
      positionAttribute.array.set(positions)
      positionAttribute.needsUpdate = true
    }
  }

  /**
   * 更新边位置
   */
  updateEdgePositions(edgeGeometry, nodePositions) {
    if (!edgeGeometry || !nodePositions) return

    const positionAttribute = edgeGeometry.attributes.position
    const edges = Object.values(this.graph.edges)
    const nodes = this.graph.nodes
    
    let vertexIndex = 0

    edges.forEach(edge => {
      const sourceNode = nodes[edge.source]
      const targetNode = nodes[edge.target]
      
      if (sourceNode && targetNode && vertexIndex + 1 < positionAttribute.count) {
        // 更新源节点位置
        const sourceIndex = sourceNode.id * 3
        positionAttribute.array[vertexIndex * 3] = nodePositions[sourceIndex]
        positionAttribute.array[vertexIndex * 3 + 1] = nodePositions[sourceIndex + 1]
        positionAttribute.array[vertexIndex * 3 + 2] = nodePositions[sourceIndex + 2]

        // 更新目标节点位置
        const targetIndex = targetNode.id * 3
        positionAttribute.array[(vertexIndex + 1) * 3] = nodePositions[targetIndex]
        positionAttribute.array[(vertexIndex + 1) * 3 + 1] = nodePositions[targetIndex + 1]
        positionAttribute.array[(vertexIndex + 1) * 3 + 2] = nodePositions[targetIndex + 2]

        vertexIndex += 2
      }
    })

    positionAttribute.needsUpdate = true
  }

  /**
   * 应用布局到几何体
   */
  applyLayout(nodeGeometry, layoutType = 'force') {
    if (!nodeGeometry) return

    const positionAttribute = nodeGeometry.attributes.position
    const nodeCount = positionAttribute.count

    switch (layoutType) {
      case 'circle':
        this.applyCircleLayout(positionAttribute, nodeCount)
        break
      case 'spiral':
        this.applySpiralLayout(positionAttribute, nodeCount)
        break
      case 'cube':
        this.applyCubeLayout(positionAttribute, nodeCount)
        break
      case 'random':
        this.applyRandomLayout(positionAttribute, nodeCount)
        break
      default:
        // 'force' 布局由物理模拟器处理
        break
    }

    positionAttribute.needsUpdate = true
  }

  /**
   * 圆形布局
   */
  applyCircleLayout(positionAttribute, nodeCount) {
    const radius = 500
    
    for (let i = 0; i < nodeCount; i++) {
      const angle = (i / nodeCount) * Math.PI * 2
      
      positionAttribute.array[i * 3] = Math.cos(angle) * radius
      positionAttribute.array[i * 3 + 1] = Math.sin(angle) * radius
      positionAttribute.array[i * 3 + 2] = 0
    }
  }

  /**
   * 螺旋布局
   */
  applySpiralLayout(positionAttribute, nodeCount) {
    const maxRadius = 800
    
    for (let i = 0; i < nodeCount; i++) {
      const t = i / nodeCount
      const angle = t * Math.PI * 10 // 10圈螺旋
      const radius = t * maxRadius
      
      positionAttribute.array[i * 3] = Math.cos(angle) * radius
      positionAttribute.array[i * 3 + 1] = Math.sin(angle) * radius
      positionAttribute.array[i * 3 + 2] = (t - 0.5) * 200 // Z轴变化
    }
  }

  /**
   * 立方体网格布局
   */
  applyCubeLayout(positionAttribute, nodeCount) {
    const size = Math.ceil(Math.cbrt(nodeCount)) // 立方体边长
    const spacing = 100
    
    for (let i = 0; i < nodeCount; i++) {
      const x = i % size
      const y = Math.floor(i / size) % size
      const z = Math.floor(i / (size * size))
      
      positionAttribute.array[i * 3] = (x - size / 2) * spacing
      positionAttribute.array[i * 3 + 1] = (y - size / 2) * spacing
      positionAttribute.array[i * 3 + 2] = (z - size / 2) * spacing
    }
  }

  /**
   * 随机布局
   */
  applyRandomLayout(positionAttribute, nodeCount) {
    const range = 1000
    
    for (let i = 0; i < nodeCount; i++) {
      positionAttribute.array[i * 3] = (Math.random() - 0.5) * range
      positionAttribute.array[i * 3 + 1] = (Math.random() - 0.5) * range
      positionAttribute.array[i * 3 + 2] = (Math.random() - 0.5) * range
    }
  }

  /**
   * 高亮节点
   */
  highlightNodes(nodeGeometry, nodeIndices, color = [1, 0, 0]) {
    if (!nodeGeometry || !nodeIndices.length) return

    const colorAttribute = nodeGeometry.attributes.color
    
    nodeIndices.forEach(index => {
      if (index < colorAttribute.count) {
        colorAttribute.array[index * 3] = color[0]
        colorAttribute.array[index * 3 + 1] = color[1]
        colorAttribute.array[index * 3 + 2] = color[2]
      }
    })

    colorAttribute.needsUpdate = true
  }

  /**
   * 重置节点颜色
   */
  resetNodeColors(nodeGeometry) {
    if (!nodeGeometry) return

    const colorAttribute = nodeGeometry.attributes.color
    const nodes = Object.values(this.graph.nodes).sort((a, b) => a.id - b.id)
    
    nodes.forEach((node, index) => {
      const degree = node.getDegree()
      const intensity = Math.min(1, degree / 10)
      
      colorAttribute.array[index * 3] = 0.5 + intensity * 0.5
      colorAttribute.array[index * 3 + 1] = 0.3 + intensity * 0.7
      colorAttribute.array[index * 3 + 2] = 0.8 + intensity * 0.2
    })

    colorAttribute.needsUpdate = true
  }
}
